package com.jxpanda.spring.module.auth.core.authentication.manager;

import com.jxpanda.spring.module.auth.core.authentication.token.CollaborativeAuthenticationToken;
import com.jxpanda.spring.module.auth.core.authentication.token.OAuth2UserCollaborativeAuthenticationToken;
import com.jxpanda.spring.module.auth.core.component.CaptchaReactiveService;
import com.jxpanda.spring.module.auth.core.exception.CaptchaNotValidException;
import com.jxpanda.spring.module.auth.core.user.CaptchaOAuth2User;
import com.jxpanda.spring.module.auth.core.user.WechatOAuth2User;
import com.jxpanda.spring.module.auth.endpoint.GrantType;
import com.jxpanda.spring.module.auth.endpoint.OAuth2Request;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import reactor.core.publisher.Mono;

/**
 * 微信小程序认证管理器
 */
public class CaptchaReactiveAuthenticationManager implements CollaborativeReactiveAuthenticationManager {

    private final CaptchaReactiveService captchaReactiveService;

    public CaptchaReactiveAuthenticationManager(CaptchaReactiveService captchaReactiveService) {
        this.captchaReactiveService = captchaReactiveService;
    }

    @Override
    public Mono<CollaborativeAuthenticationToken> authenticate(CollaborativeAuthenticationToken collaborativeAuthenticationToken) {
        OAuth2Request oAuth2Request = collaborativeAuthenticationToken.getOAuth2Request();
        String captcha = oAuth2Request.getCaptcha();
        String grantType = oAuth2Request.getGrantType();
        String identifier;
        if (grantType.equals(GrantType.PHONE_CAPTCHA.getValue())) {
            identifier = oAuth2Request.getPhone();
        } else {
            identifier = oAuth2Request.getEmail();
        }
        return captchaReactiveService.isCaptchaValid(identifier, captcha)
                .filter(valid -> valid)
                .switchIfEmpty(Mono.defer(() -> Mono.error(new CaptchaNotValidException())))
                .map(it -> buildAuthenticationToken(identifier, oAuth2Request, collaborativeAuthenticationToken.getClientRegistration()));
    }

    private static OAuth2UserCollaborativeAuthenticationToken buildAuthenticationToken(String identifier, OAuth2Request oAuth2Request, ClientRegistration clientRegistration) {
        CaptchaOAuth2User captchaOAuth2User = new CaptchaOAuth2User(identifier, clientRegistration.getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName());
        return new OAuth2UserCollaborativeAuthenticationToken(oAuth2Request, clientRegistration, captchaOAuth2User);
    }

}
